-- $Id: $
-- File name:   ENCODE.vhd
-- Created:     11/28/2010
-- Author:      Alyssa Welles
-- Lab Section: 337-04
-- Version:     1.0  Initial Design Entry
-- Description: Encoder for Transmitter


LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.std_logic_arith.ALL;
USE IEEE.std_logic_unsigned.ALL;


entity ENCODE is
    port( CLK : in std_logic;
        RST_N : in std_logic;
 SHIFT_ENABLE : in std_logic;
       D_ORIG : in std_logic;
        EMPTY : in std_logic; 
       D_PLUS : out std_logic;
      D_MINUS : out std_logic;
    NEWPACKET : out std_logic;  
   SHIFT_UPDT : out std_logic;  
     CRC_FLAG : out std_logic  
        );
end ENCODE;

architecture BEHAVIORAL of ENCODE is
 type stateType is (IDLE, PRIMARY, SECONDARY, BITSTUFF1, BITSTUFF2, CRCOUT);
 signal state, nextstate : stateType;
 signal oldenc, currenc, nextcurr : std_logic; 
 signal crcflag : std_logic;
 signal count, nextcount : std_logic_vector(3 downto 0);
 signal crc_count, nextcrc_count : std_logic_vector(4 downto 0);
 signal onesbits, nextones : std_logic_vector(2 downto 0);
 signal shift_sig : std_logic;
 signal crc, nextcrc : std_logic_vector(15 downto 0);

begin
  
--------------------------------------------------------------------
--********************** Flip Flops ******************************--
--------------------------------------------------------------------
    
 streg: process (CLK, RST_N)
 begin
  IF RST_N = '0' THEN
   state <= IDLE;
   oldenc <= '1';
  ELSIF CLK'event AND CLK = '1' THEN
   state <= nextstate;
   oldenc <= currenc;
  END IF;
 END process streg;
 
 extraFF : process(RST_N, CLK)
 begin 
   IF RST_N = '0' THEN
     nextcurr <= '0';
   ELSIF CLK'EVENT AND CLK = '1' THEN
     nextcurr <= currenc;
   END IF;
 end process extraFF; 
 
--------------------------------------------------------------------
--********************** BIT COUNTER & ADDER *********************--
--------------------------------------------------------------------
 
 btcount : process (CLK, RST_N)
 begin
  IF RST_N = '0' THEN
    count <= "0000";
    crc_count <= "00000";
    onesbits <= "000";
  ELSIF CLK'event AND CLK = '1' THEN
    count <= nextcount;
    crc_count <= nextcrc_count;
    onesbits <= nextones;
  END IF;   
 end process btcount;
 
 addcnt : process (SHIFT_ENABLE, D_ORIG, count, onesbits, crcflag)
 begin
  IF crcflag = '1' THEN
    nextcount <= count;
    nextones <= onesbits;
  ELSIF onesbits = "110" THEN
    nextcount <= count;
    nextones <= "000";
  ELSIF count = "1000" THEN
    nextcount <= "0000";
    nextones <= onesbits;
  ELSIF SHIFT_ENABLE = '1' AND D_ORIG = '1' AND shift_sig = '1' THEN
    nextcount <= count + 1;
    nextones <= onesbits + 1;
  ELSIF SHIFT_ENABLE = '0' AND D_ORIG = '1' AND shift_sig = '1' THEN
    nextcount <= count;
    nextones <= onesbits;    
  ELSIF SHIFT_ENABLE = '1' AND D_ORIG = '0' AND shift_sig = '1' THEN
    nextcount <= count + 1;
    nextones <= "000";
  ELSE                                       
    nextcount <= count;
    nextones <= onesbits;
  END IF;
 end process addcnt;
  
 crccnt : process(SHIFT_ENABLE, crcflag, crc_count)
 begin 
  IF SHIFT_ENABLE = '1' AND crcflag = '1' THEN
    nextcrc_count <= crc_count + 1;
  ELSIF crc_count = "10000" AND crcflag = '1' THEN
    nextcrc_count <= "00000";
  ELSE
    nextcrc_count <= crc_count;
  END IF;
 end process crccnt;  
 
--------------------------------------------------------------------
--********************** CRC DATA LOGIC **************************--
--------------------------------------------------------------------
 crc_reg: process (CLK, RST_N)
 begin
  if (RST_N = '0') then
    crc <= (others => '0');
  elsif (CLK'event and CLK = '1') then      
    crc <= nextcrc;
  end if; 
 end process crc_reg; 
 
 crc_shft: process(D_ORIG, SHIFT_ENABLE, shift_sig, crc_count)
 begin
   if crc_count = "00000" then
     nextcrc <= "1111111111111111";
   elsif SHIFT_ENABLE = '1' AND shift_sig = '1' then
     nextcrc(15) <= crc(14);
     nextcrc(14) <= crc(13);
     nextcrc(13) <= crc(12) xor crc(15);
     nextcrc(12) <= crc(11);
     nextcrc(11) <= crc(10);
     nextcrc(10) <= crc(9);
     nextcrc(9) <= crc(8);
     nextcrc(8) <= crc(7);
     nextcrc(7) <= crc(6);
     nextcrc(6) <= crc(5) xor crc(15);
     nextcrc(5) <= crc(4);
     nextcrc(4) <= crc(3);
     nextcrc(3) <= crc(2);
     nextcrc(2) <= crc(1);
     nextcrc(1) <= crc(0) xor crc(15);
     nextcrc(0) <= D_ORIG;     
   else
     nextcrc <= crc;
   end if;
   
 end process crc_shft;  
 
--------------------------------------------------------------------
--********************** NEXT STATE LOGIC ************************--
--------------------------------------------------------------------
   
 nxtst: process(state, count, crc_count, onesbits, SHIFT_ENABLE, EMPTY)
 begin
   
  CASE state IS
     
   WHEN IDLE =>      -- IDLE state before the data byte is transmitted
    IF EMPTY = '1' THEN
     nextstate <= IDLE;
    ELSE
     nextstate <= PRIMARY;
    END IF;
    
   WHEN PRIMARY =>   -- Transmit the first bit of the data byte
    IF onesbits = "110" AND SHIFT_ENABLE = '1' THEN
     nextstate <= BITSTUFF1;
    ELSIF SHIFT_ENABLE = '0' THEN
     nextstate <= PRIMARY;
    ELSE
     nextstate <= SECONDARY;
    END IF;
    
   WHEN SECONDARY => -- Transmit data after the first bit of the data byte
    IF onesbits = "110" THEN 
     nextstate <= BITSTUFF1;
    ELSIF count = "1000" THEN
     nextstate <= CRCOUT;
    ELSE
     nextstate <= SECONDARY;
    END IF;
    
   WHEN BITSTUFF1 => -- SHIFT_ENABLE should be low for one transmission clock cycle
    IF SHIFT_ENABLE = '1' THEN
     nextstate <= BITSTUFF2;
    ELSE
     nextstate <= BITSTUFF1;
    END IF;

   WHEN BITSTUFF2 => -- After a stuffed bit has been transmitted
    IF SHIFT_ENABLE = '1' THEN
     nextstate <= SECONDARY;
    ELSE
     nextstate <= BITSTUFF2;
    END IF;
    
   WHEN CRCOUT =>    -- Output the CRC
    IF crc_count = "10000" THEN
     nextstate <= IDLE;
    ELSE
     nextstate <= CRCOUT;
    END IF;
 
   WHEN others =>
    nextstate <= IDLE;  
  
  END CASE;
 end process nxtst;

--------------------------------------------------------------------
--********************** OUTPUT LOGIC ****************************--
--------------------------------------------------------------------
 encd: process(state, oldenc, D_ORIG, SHIFT_ENABLE)
 begin
  currenc <= nextcurr;
  CASE state IS
     
   WHEN IDLE =>      -- IDLE state before the data byte is transmitted
    currenc <= oldenc;
    shift_sig <= '1';
    NEWPACKET <= '1';
    crcflag <= '0';
    
   WHEN PRIMARY =>   -- Transmit the first bit of the data byte
    shift_sig <= '1';
    NEWPACKET <= '0';
    crcflag <= '0';
    IF D_ORIG = '0' THEN
     currenc <= '0'; 
    ELSE
     currenc <= '1';
    END IF;
    
   WHEN SECONDARY => -- Transmit data after the first bit of the data byte
    shift_sig <= '1';
    IF count = "0000" THEN
     currenc <= oldenc;
     NEWPACKET <= '1';
     crcflag <= '0';
    ELSIF D_ORIG = '0' AND SHIFT_ENABLE = '1' AND count = "1000" THEN 
     currenc <= NOT(oldenc);
     NEWPACKET <= '0';
     crcflag <= '1';
    ELSIF D_ORIG = '0' AND SHIFT_ENABLE = '1' THEN 
     currenc <= NOT(oldenc);
     NEWPACKET <= '0';
     crcflag <= '0';     
    ELSIF D_ORIG = '1' AND SHIFT_ENABLE = '1' AND count = "1000" THEN
     currenc <= oldenc;
     NEWPACKET <= '0';
     crcflag <= '1'; 
    ELSIF D_ORIG = '1' AND SHIFT_ENABLE = '1' THEN
     currenc <= oldenc;
     NEWPACKET <= '0';
     crcflag <= '0';  
    ELSE 
     currenc <= oldenc; 
     NEWPACKET <= '0';
     crcflag <= '0';
    END IF;
    
   WHEN BITSTUFF1 => -- SHIFT_ENABLE should be low for one transmission clock cycle
    currenc <= '0';
    shift_sig <= '0';
    NEWPACKET <= '0';
    crcflag <= '0';
    
   WHEN BITSTUFF2 => -- After a stuffed bit has been transmitted
    shift_sig <= '1';
    currenc <= '1'; 
    crcflag <= '0';
    
   WHEN CRCOUT =>    -- Output the CRC
    crcflag <= '1';      
    currenc <= crc(15);
           
    
  END CASE; 
 END process encd;
 
 SHIFT_UPDT <= shift_sig;
 CRC_FLAG <= crcflag;
 D_PLUS <= nextcurr when crcflag = '0' 
                 else '1';
 D_MINUS <= not(nextcurr) when crcflag = '0'
                 else '1';   
                                
end BEHAVIORAL; 

